// 当前处理的 fiber 节点，根 fiber 节点
let nextFiberReconcileWork = null;
let wipRoot = null;

// 这是一个空闲调度器
function workLoop(deadline) {
	let shouldYield = false;

	// 循环处理完所有的 
	while (nextFiberReconcileWork && !shouldYield) {
			nextFiberReconcileWork = performNextWork(
				nextFiberReconcileWork
			);

			// 如果有下一个 fiber 且有空闲时间
			shouldYield = deadline.timeRemaining() < 1;
	}

	// 全都 把 节点转成了 fiber 节点
	if (!nextFiberReconcileWork) {
			commitRoot();
	}

	requestIdleCallback(workLoop)
}

requestIdleCallback(workLoop)

function performNextWork(fiber) {
	reconcile(fiber)

	// 先找子元素
	if (fiber.child) {
		return fiber.child
	}
	let nextFiber = fiber

	while(nextFiber) {
		// 兄弟元素
		if (nextFiber.sibling) {
			return nextFiber.sibling
		}

		// 再找父元素
		nextFiber = nextFiber.return
	}
}

function render(element, container) {
    wipRoot = {
        dom: container,
        props: {
            children: [element],
        }
    }
    nextFiberReconcileWork = wipRoot
}

function reconcile(fiber) {
    if (!fiber.dom) {
        fiber.dom = createDom(fiber)
    }
    reconcileChildren(fiber, fiber.props.children)
}

function reconcileChildren(wipFiber, elements) {
	let index = 0
	let prevSibling = null
	while(
		index < elements.length
	) {
		const element = elements[index]
		let newFiber = {
			type: element.type,
			props: element.props,
			dom: null,
			return: wipFiber,
			effectTag: "PLACEMENT",
		}

		if (index === 0) {
			wipFiber.child = newFiber
		} else if (element) {
			prevSibling.sibling = newFiber
		}

		prevSibling = newFiber
		index++
	}
}

function commitRoot() {
	commitWork(wipRoot.child);
	wipRoot = null
}

function commitWork(fiber) {
	if (!fiber) {
		return
	}

	let domParentFiber = fiber.return

	while(!domParentFiber.dom) {
		domParentFiber = domParentFiber.return
	}
	const domParent = domParentFiber.dom

	if (
		fiber.effectTag === 'PLACEMENT' &&
		fiber.dom != null
	) {
		domParent.appendChild(fiber.dom)
	}
	commitWork(fiber.child)
	commitWork(fiber.sibling)
}
function createDom(fiber) {
    const dom = fiber.type == "TEXT_ELEMENT" ? document.createTextNode("") : document.createElement(fiber.type);

    for (const prop in fiber.props) {
        setAttribute(dom, prop, fiber.props[prop]);
    }

    return dom;
}